#nullable enable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PHMEE.Entities.BaseInfo.Units;
using PHMEE.PHM.Algorithms.Diagnosis;
using Volo.Abp.Domain.Services;

namespace PHMEE.Managers.Diagnosis;

/// <summary>
/// 滑油-燃油分油机故障诊断
/// </summary>
public class OilFuelSeparatorFaultDiagnosisDomainService : DomainService, IOilFuelSeparatorFaultDiagnosisDomainService
{
    private readonly OilFuelSeparatorAlg _oilFuelSeparatorAlg;
    private readonly IBearingParametersDomainService _bearingParametersDomainService;

    public OilFuelSeparatorFaultDiagnosisDomainService(
        OilFuelSeparatorAlg oilFuelSeparatorAlg,
        IBearingParametersDomainService bearingParametersDomainService)
    {
        _oilFuelSeparatorAlg = oilFuelSeparatorAlg;
        _bearingParametersDomainService = bearingParametersDomainService;
    }

    /// <summary>
    /// 滑油-燃油分油机故障诊断
    /// </summary>
    /// <param name="pointPosition"></param>
    /// <param name="sampleRate"></param>
    /// <param name="unitWithEquips"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public async Task<string[]> FaultDiagnosisAsync(PointPosition pointPosition, float sampleRate,
        UnitWithEquipsDto unitWithEquips,
        float[] data)
    {
        // 设备参数和阈值初始化
        var equipmentParameters = new OilFuelSeparatorEquipmentParameters();
        var thresholds = new OilFuelSeparatorThresholds();

        // 验证并提取设备信息
        var (asynchronousElectricMotor, fuelOilSeparatorGear) = ValidateAndExtractUnitEquipments(unitWithEquips.UnitEquips);

        // 提取异步电动机参数
        ExtractAsynchronousElectricMotorParameters(asynchronousElectricMotor, equipmentParameters);

        // 提取分油机参数
        ExtractFuelOilSeparatorGearParameters(fuelOilSeparatorGear, equipmentParameters);

        // 提取轴承信息
        await ExtractBearingParametersAsync(asynchronousElectricMotor, fuelOilSeparatorGear, equipmentParameters);
        
        // 提取阈值信息
        ExtractThresholds(unitWithEquips.Unit, thresholds);

        // 调用滑油-燃油分油机故障诊断算法
        var response = await _oilFuelSeparatorAlg.OilFuelSeparatorAsync(pointPosition, data, sampleRate,
            equipmentParameters, thresholds);
        
        return response.FaultCodes.ToArray();
    }

    private static (AsynElectricMotor, FuelOilSeparatorGear) ValidateAndExtractUnitEquipments(List<Equipment> unitEquips)
    {
        if (unitEquips.Count == 0)
        {
            throw new InvalidOperationException(nameof(Equipment));
        }

        if ((unitEquips.FirstOrDefault(e => e.Type == EquipmentEnum.AsynElectricMotor)
             ?? throw new InvalidOperationException(nameof(EquipmentEnum.AsynElectricMotor)))
            is not AsynElectricMotor asynchronousElectricMotorEquip)
        {
            throw new InvalidOperationException(nameof(AsynElectricMotor));
        }

        asynchronousElectricMotorEquip.DeserializeProperties();

        if ((unitEquips.FirstOrDefault(e => e.Type == EquipmentEnum.FuelOilSeparatorGear)
             ?? throw new InvalidOperationException(nameof(EquipmentEnum.FuelOilSeparatorGear)))
            is not FuelOilSeparatorGear fuelOilSeparatorGearEquip)
        {
            throw new InvalidOperationException(nameof(FuelOilSeparatorGear));
        }

        fuelOilSeparatorGearEquip.DeserializeProperties();

        return (asynchronousElectricMotorEquip, fuelOilSeparatorGearEquip);
    }
    
    private static void ExtractAsynchronousElectricMotorParameters(AsynElectricMotor asynchronousElectricMotor,
        OilFuelSeparatorEquipmentParameters equipmentParameters)
    {
        equipmentParameters.Rpm = (float)asynchronousElectricMotor.MotorSpeed;
        equipmentParameters.Lf = (float)asynchronousElectricMotor.Frequency;
        equipmentParameters.Rbpf = (float)asynchronousElectricMotor.RotorBarsNumber;
        equipmentParameters.Power = (float)asynchronousElectricMotor.Power;
    }
    
    private static void ExtractFuelOilSeparatorGearParameters(FuelOilSeparatorGear fuelOilSeparatorGear,
        OilFuelSeparatorEquipmentParameters equipmentParameters)
    {
        equipmentParameters.Z1 = (float)fuelOilSeparatorGear.BigTeethNumber;
        equipmentParameters.Z2 = (float)fuelOilSeparatorGear.SmallTeethNumber;
        equipmentParameters.VRpm = (float)fuelOilSeparatorGear.Speed;
    }
    
    private async Task ExtractBearingParametersAsync(AsynElectricMotor asynchronousElectricMotor,
        FuelOilSeparatorGear fuelOilSeparatorGear,
        OilFuelSeparatorEquipmentParameters equipmentParameters)
    {
        equipmentParameters.BearMotorDrive.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(asynchronousElectricMotor.DriveEndBearFactoryFirst, asynchronousElectricMotor.DriveEndBearModelFirst));
        equipmentParameters.BearMotorFree.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(asynchronousElectricMotor.NonDriveEndBearFactory, asynchronousElectricMotor.NonDriveEndBearModel));
        
        equipmentParameters.BearHorizontalAxisDrive.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(fuelOilSeparatorGear.HorDriveEndBearFactory, fuelOilSeparatorGear.HorDriveEndBearModel));
        equipmentParameters.BearHorizontalAxisFree.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(fuelOilSeparatorGear.HorNonDriveEndBearFactory, fuelOilSeparatorGear.HorNonDriveEndBearModel));
        equipmentParameters.BearVerticalAxisUpper.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(fuelOilSeparatorGear.UpBearFactory, fuelOilSeparatorGear.UpBearModel));
        equipmentParameters.BearVerticalAxisLower.AddRange(await _bearingParametersDomainService.GetBearingParametersAsync(fuelOilSeparatorGear.DownBearFactory, fuelOilSeparatorGear.DownBearModel));
    }
    
    /// <summary>
    /// 从 Unit 提取阈值
    /// </summary>
    /// <param name="unit"></param>
    /// <param name="thresholds"></param>
    /// <exception cref="InvalidOperationException"></exception>
    private static void ExtractThresholds(Unit unit, OilFuelSeparatorThresholds thresholds)
    {
        if (unit is FuelOilSeparatorUnit fuelOilSeparatorUnit)
        {
            ExtractThresholdsForFuelOilSeparator(fuelOilSeparatorUnit, thresholds);
        }
        else if (unit is LubricatingOilSepaUnit lubricatingOilSepaUnit)
        {
            ExtractThresholdsForFuelOilSeparator(lubricatingOilSepaUnit, thresholds);
        }
        else
        {
            throw new InvalidOperationException($"There is no '{unit.GetType().Name}' in OilFuelSeparatorUnit.");
        }
    }
    
    /// <summary>
    /// 燃油分油机机组阈值提取
    /// </summary>
    /// <param name="unit"></param>
    /// <param name="thresholds"></param>
    private static void ExtractThresholdsForFuelOilSeparator(FuelOilSeparatorUnit unit, OilFuelSeparatorThresholds thresholds)
    {
        unit.DeserializeProperties();
        
        thresholds.Acc = (float)unit.Acc;
        thresholds.MRms.AddRange(new[] { (float)unit.MrmsA, (float)unit.MrmsB, (float)unit.MrmsC });
        thresholds.Value1X.AddRange(new[] { (float)unit.Value1XA, (float)unit.Value1XB });
        thresholds.Bear.AddRange(new[]
        {
            (float)unit.BearA,
            (float)unit.BearB,
            (float)unit.BearC,
            (float)unit.BearD,
            (float)unit.BearE1,
            (float)unit.BearE2,
            (float)unit.BearE3,
            (float)unit.BearE4,
            (float)unit.BearE5
        });
        thresholds.ArmatureFault.AddRange(new[] { (float)unit.ArmatureFaultA, (float)unit.ArmatureFaultB });
        thresholds.ResonanceFault = (float)unit.ResonanceFault;
        thresholds.StructureLoose = (float)unit.StructureLoose;
        thresholds.Misalignment.AddRange(new[] { (float)unit.MisalignmentA, (float)unit.MisalignmentB });
        thresholds.HRms.AddRange(new[] { (float)unit.HrmsA, (float)unit.HrmsB, (float)unit.HrmsC });
        thresholds.ImbalanceFault = (float)unit.ImbalanceFault;
        thresholds.SpiralGear.AddRange(new[]
        {
            (float)unit.SpiralGearA,
            (float)unit.SpiralGearB,
            (float)unit.SpiralGearC,
            (float)unit.SpiralGearD
        });
        thresholds.SpiralGearPoorMeshing = (float)unit.SpiralGearPoorMeshing;
    }
    
    /// <summary>
    /// 滑油分油机机组阈值提取
    /// </summary>
    /// <param name="unit"></param>
    /// <param name="thresholds"></param>
    private static void ExtractThresholdsForFuelOilSeparator(LubricatingOilSepaUnit unit, OilFuelSeparatorThresholds thresholds)
    {
        unit.DeserializeProperties();
        
        thresholds.Acc = (float)unit.Acc;
        thresholds.MRms.AddRange(new[] { (float)unit.MrmsA, (float)unit.MrmsB, (float)unit.MrmsC });
        thresholds.Value1X.AddRange(new[] { (float)unit.Value1XA, (float)unit.Value1XB });
        thresholds.Bear.AddRange(new[]
        {
            (float)unit.BearA,
            (float)unit.BearB,
            (float)unit.BearC,
            (float)unit.BearD,
            (float)unit.BearE1,
            (float)unit.BearE2,
            (float)unit.BearE3,
            (float)unit.BearE4,
            (float)unit.BearE5
        });
        thresholds.ArmatureFault.AddRange(new[] { (float)unit.ArmatureFaultA, (float)unit.ArmatureFaultB });
        thresholds.ResonanceFault = (float)unit.ResonanceFault;
        thresholds.StructureLoose = (float)unit.StructureLoose;
        thresholds.Misalignment.AddRange(new[] { (float)unit.MisalignmentA, (float)unit.MisalignmentB });
        thresholds.HRms.AddRange(new[] { (float)unit.HrmsA, (float)unit.HrmsB, (float)unit.HrmsC });
        thresholds.ImbalanceFault = (float)unit.ImbalanceFault;
        thresholds.SpiralGear.AddRange(new[]
        {
            (float)unit.SpiralGearA,
            (float)unit.SpiralGearB,
            (float)unit.SpiralGearC,
            (float)unit.SpiralGearD
        });
        thresholds.SpiralGearPoorMeshing = (float)unit.SpiralGearPoorMeshing;
    }
}